package cn.glutnn.subject.domain.service.impl;

import cn.glutnn.subject.common.enums.CategoryTypeEnum;
import cn.glutnn.subject.common.enums.IsDeletedFlagEnum;
import cn.glutnn.subject.domain.convert.SubjectCategoryConverter;
import cn.glutnn.subject.domain.convert.SubjectLabelConverter;
import cn.glutnn.subject.domain.enyity.SubjectCategoryBO;
import cn.glutnn.subject.domain.enyity.SubjectLabelBO;
import cn.glutnn.subject.domain.service.SubjectCategoryDomainService;
import cn.glutnn.subject.domain.util.CacheUtil;
import cn.glutnn.subject.infra.basic.entity.SubjectCategory;
import cn.glutnn.subject.infra.basic.entity.SubjectLabel;
import cn.glutnn.subject.infra.basic.entity.SubjectMapping;
import cn.glutnn.subject.infra.basic.service.SubjectCategoryService;
import cn.glutnn.subject.infra.basic.service.SubjectLabelService;
import cn.glutnn.subject.infra.basic.service.SubjectMappingService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * Author:   msh
 * Date:     2024/11/21 上午11:31
 * Description:
 */

@Service
@Slf4j
public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {

    @Resource
    private SubjectCategoryService subjectCategoryService;
    @Resource
    private SubjectMappingService subjectMappingService;
    @Resource
    private SubjectLabelService subjectLabelService;
    @Resource
    private ThreadPoolExecutor labelThreadPool;
    @Autowired
    private CacheUtil cacheUtil;


    @Override
    public void add(SubjectCategoryBO subjectCategoryBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryDomainServiceImpl add subjectCategoryBO:{}", subjectCategoryBO);
        }
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToCategory(subjectCategoryBO);
        subjectCategoryService.save(subjectCategory);
    }

    @Override
    public List<SubjectCategoryBO> queryPrimaryCategory() {
        LambdaQueryWrapper<SubjectCategory> wrapper = new LambdaQueryWrapper<SubjectCategory>()
                .eq(SubjectCategory::getParentId, 0)
                .eq(SubjectCategory::getIsDeleted, IsDeletedFlagEnum.UN_DELETED);
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.list(wrapper);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryDomainServiceImpl queryPrimaryCategory subjectCategoryList:{}", subjectCategoryList);
        }
        List<SubjectCategoryBO> subjectCategoryBOS = SubjectCategoryConverter.INSTANCE.convertCategoryListToBoList(subjectCategoryList);
        // 获取子分类下的题目数量
        for (SubjectCategoryBO subjectCategoryBO : subjectCategoryBOS) {
            Integer count = subjectCategoryService.querySubjectCountByCategoryId(subjectCategoryBO.getId());
            subjectCategoryBO.setCount(count);
        }
        return subjectCategoryBOS;
    }

    @Override
    public List<SubjectCategoryBO> queryCategoryByPrimary(SubjectCategoryBO subjectCategoryBO) {
        LambdaQueryWrapper<SubjectCategory> wrapper = new LambdaQueryWrapper<SubjectCategory>()
                .eq(SubjectCategory::getParentId, subjectCategoryBO.getParentId())
                .eq(SubjectCategory::getIsDeleted, IsDeletedFlagEnum.UN_DELETED.getCode())
                .eq(SubjectCategory::getCategoryType, CategoryTypeEnum.SECONDARY.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.list(wrapper);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryDomainServiceImpl queryCategoryByPrimary subjectCategoryList:{}", subjectCategoryList);
        }
        return SubjectCategoryConverter.INSTANCE.convertCategoryListToBoList(subjectCategoryList);
    }

    @Override
    public void update(SubjectCategoryBO subjectCategoryBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryDomainServiceImpl update subjectCategoryBO:{}", subjectCategoryBO);
        }
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToCategory(subjectCategoryBO);
        subjectCategoryService.updateById(subjectCategory);
    }

    @Override
    public void removeById(SubjectCategoryBO subjectCategoryBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryDomainServiceImpl removeById id:{}", subjectCategoryBO.getId());
        }
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToCategory(subjectCategoryBO);
        LambdaUpdateWrapper<SubjectCategory> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(SubjectCategory::getId, subjectCategory.getId())
                .set(SubjectCategory::getIsDeleted, IsDeletedFlagEnum.DELETED.getCode());
        subjectCategoryService.update(wrapper);
    }

    @Override
    @SneakyThrows
    public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
        Long id = subjectCategoryBO.getId();
        String cacheKey = "categoryAndLabel." + id;
        return cacheUtil.getResult(cacheKey, SubjectCategoryBO.class, (key) -> getSubjectCategoryBOS(subjectCategoryBO));
    }

    private List<SubjectCategoryBO> getSubjectCategoryBOS(SubjectCategoryBO subjectCategoryBO) {
        // 查询大类下的所有子类
        LambdaQueryWrapper<SubjectCategory> wrapper = new LambdaQueryWrapper<SubjectCategory>()
                .eq(SubjectCategory::getParentId, subjectCategoryBO.getId())
                .eq(SubjectCategory::getIsDeleted, IsDeletedFlagEnum.UN_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.list(wrapper);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryDomainServiceImpl queryCategoryAndLabel subjectCategoryList:{}", subjectCategoryList);
        }
        List<SubjectCategoryBO> subjectCategoryBOList = SubjectCategoryConverter.INSTANCE.convertCategoryListToBoList(subjectCategoryList);

        List<SubjectCategoryBO> subjectCategoryBOList1 = new ArrayList<>();

        // 第二种方式
        List<CompletableFuture<SubjectCategoryBO>> completableFutureList = subjectCategoryBOList.stream().map(subjectCategoryBO1 ->
                CompletableFuture.supplyAsync(() -> subjectCategoryBO(subjectCategoryBO1), labelThreadPool)
        ).toList();
        completableFutureList.forEach(completableFuture -> {
            try {
                subjectCategoryBOList1.add(completableFuture.get());
            } catch (Exception e) {
                log.error("SubjectCategoryDomainServiceImpl queryCategoryAndLabel error:{}", e.getMessage(), e);
            }
        });

        return subjectCategoryBOList1;
    }

    private SubjectCategoryBO subjectCategoryBO(SubjectCategoryBO subjectCategoryBO1) {
        List<SubjectMapping> subjectMappingList = subjectMappingService.list(new LambdaQueryWrapper<SubjectMapping>()
                .eq(SubjectMapping::getCategoryId, subjectCategoryBO1.getId()));
        if (CollectionUtils.isEmpty(subjectMappingList)) {
            return null;
        }
        List<Long> labelIdList = subjectMappingList.stream().map(SubjectMapping::getLabelId).toList();
        List<SubjectLabel> subjectLabels = subjectLabelService.listByIds(labelIdList);
        subjectCategoryBO1.setLabelBOList(SubjectLabelConverter.INSTANCE.convertLabelListToBoList(subjectLabels));
        return subjectCategoryBO1;
    }

    private Map<Long, List<SubjectLabelBO>> getLabelBOList(SubjectCategoryBO subjectCategoryBO1) {
        Map<Long, List<SubjectLabelBO>> labelMap = new HashMap<>();
        List<SubjectMapping> subjectMappingList = subjectMappingService.list(new LambdaQueryWrapper<SubjectMapping>()
                .eq(SubjectMapping::getCategoryId, subjectCategoryBO1.getId()));
        if (CollectionUtils.isEmpty(subjectMappingList)) {
            return null;
        }
        List<Long> labelIdList = subjectMappingList.stream().map(SubjectMapping::getLabelId).toList();
        List<SubjectLabel> subjectLabels = subjectLabelService.listByIds(labelIdList);
        subjectCategoryBO1.setLabelBOList(SubjectLabelConverter.INSTANCE.convertLabelListToBoList(subjectLabels));
        labelMap.put(subjectCategoryBO1.getId(), subjectCategoryBO1.getLabelBOList());
        return labelMap;
    }
}
